package main

import (
	"fmt"
	"os"
	"path"
	"path/filepath"

	"golang.org/x/tools/go/packages"
)

// androidPkgName sanitizes the go package name to be acceptable as a android
// package name part. The android package name convention is similar to the
// java package name convention described in
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.5.3.1
// but not exactly same.
func androidPkgName(name string) string {
	var res []rune
	for _, r := range name {
		switch {
		case 'a' <= r && r <= 'z', 'A' <= r && r <= 'Z', '0' <= r && r <= '9':
			res = append(res, r)
		default:
			res = append(res, '_')
		}
	}
	if len(res) == 0 || res[0] == '_' || ('0' <= res[0] && res[0] <= '9') {
		// Android does not seem to allow the package part starting with _.
		res = append([]rune{'g', 'o'}, res...)
	}
	s := string(res)
	// Look for Java keywords that are not Go keywords, and avoid using
	// them as a package name.
	//
	// This is not a problem for normal Go identifiers as we only expose
	// exported symbols. The upper case first letter saves everything
	// from accidentally matching except for the package name.
	//
	// Note that basic type names (like int) are not keywords in Go.
	switch s {
	case "abstract", "assert", "boolean", "byte", "catch", "char", "class",
		"do", "double", "enum", "extends", "final", "finally", "float",
		"implements", "instanceof", "int", "long", "native", "private",
		"protected", "public", "short", "static", "strictfp", "super",
		"synchronized", "this", "throw", "throws", "transient", "try",
		"void", "volatile", "while":
		s += "_"
	}
	return s
}

func packagesConfig(env []string) *packages.Config {
	config := &packages.Config{}
	// Add CGO_ENABLED=1 explicitly since Cgo is disabled when GOOS is different from host OS.
	config.Env = append(os.Environ(), env...)

	/*
		tags := buildTags
		if len(tags) > 0 {
			config.BuildFlags = []string{"-tags=" + strings.Join(tags, ",")}
		}
	*/

	return config
}

func tryBuild(args []string) int {
	env, err := buildEnvInit("arm64", 30)
	if err != nil {
		fmt.Println("env, err, ", err)
	}

	/**/
	for i, v := range env {
		fmt.Printf(" %d: %s\n", i, v)
	}

	pkgs, err := packages.Load(packagesConfig(env), ".")
	if err != nil {
		fmt.Println("env, err, ", err)
		return 1
	}
	// len(pkgs) can be more than 1 e.g., when the specified path includes `...`.
	if len(pkgs) != 1 {
		return 2
	}

	for _, pkg := range pkgs {
		fmt.Println("name:", pkg.Name)
		fmt.Println("path:", pkg.PkgPath)
		fmt.Println("files:", pkg.GoFiles)
	}

	pkg := pkgs[0]

	if pkg.Name != "main" {
		fmt.Println("pkg, err, ", fmt.Errorf("cannot set -o when building non-main package"))
		return 3
	}

	{
		appName := path.Base(pkg.PkgPath)
		libName := androidPkgName(appName)

		toolchain := ndk.Toolchain("arm64")
		libPath := "lib/" + toolchain.abi + "/lib" + libName + ".so"
		libAbsPath := filepath.Join(".//", libPath)
		if err := os.MkdirAll(filepath.Dir(libAbsPath), 0755); err != nil {
			fmt.Println("mkdir, err, ", err)
			return 11
		}

		err = goBuild(
			pkg.PkgPath,
			env,
			"-buildmode=c-shared",
			"-o", libAbsPath,
		)
		if err != nil {
			fmt.Println("build, err, ", err)
			return 12
		}
	}

	return 0
}
